import json
import datetime

from django.urls import reverse

from utils.encrypt import uid
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from django.utils.safestring import mark_safe
from django.views.decorators.csrf import csrf_exempt
from utils.Pagination import Pagination
from web import models
from web.form.issues import IssuesModelForm, RecordModelForm, InviteModelForm


class Checkfilt():
    def __init__(self, name, data, request):
        self.name = name
        self.data = data
        self.request = request

    def __iter__(self):
        for item in self.data:
            key = str(item[0])
            text = item[1]
            # 循环对比出是否被选中
            ck = ""
            value_list = self.request.GET.getlist(self.name)
            if key in value_list:
                ck = "checked"  # 通过每次循环对比，将url中有的参数的选项属性改为已选
                value_list.remove(key)
            else:
                value_list.append(key)  # 此时的vlue_list只有这个格子的值，不会有其他的值，每次循环都会重置vlue_list，可用来生成url。

            # 生成每个标签自己的url
            query_dict = self.request.GET.copy()  # 将url中的参数复制下来进行修改，为一个字典{"status":1,"priority":2}
            query_dict._mutable = True
            if query_dict.get("page"):
                query_dict.pop("page")  # 这里将每次的页码参数删掉，不加到筛选的url里。
            query_dict.setlist(self.name,
                               value_list)  # 只将这单个参数值赋成最新的，因为上面的循环处理value_list，如果页面上已选择，这里参数值就没有了，如果页面上未选择，这里参数值就有
            param_url = query_dict.urlencode()  # 这里还要将字典转换成url参数格式 status=1&priority=2
            if param_url:  # 这里不能判断字典，因为字典只是value为空，key不为空{'issues_type': []}
                url = "{}?{}".format(self.request.path_info, param_url)  # 在这对域名和参数进行拼接生成url
            else:
                url = self.request.path_info
            tpl = '<a class="cell" href="{url}"><input type="checkbox" {ck} /><label>{text}</label></a>'.format(url=url,
                                                                                                                ck=ck,
                                                                                                                text=text)
            yield mark_safe(tpl)


class Selectfilt():
    def __init__(self, name, data, request):
        self.name = name
        self.data = data
        self.request = request

    def __iter__(self):
        # 定好data为人员数据[(1,jack),(2,he)]
        yield mark_safe("<select class='select2' multiple='multiple' style='width:100%;'>")
        for item in self.data:
            selected = ""
            key = str(item[0])
            text = item[1]
            value_list = self.request.GET.getlist(self.name)
            if key in value_list:
                selected = "selected"
                value_list.remove(key)
            else:
                value_list.append(key)

            value_dict = self.request.GET.copy()
            value_dict._mutable = True
            if value_dict.get("page"):
                value_dict.pop("page")
            value_dict.setlist(self.name, value_list)
            url_parm = value_dict.urlencode()
            if url_parm:
                url = "{}?{}".format(self.request.path_info, url_parm)
            else:
                url = self.request.path_info
            yield mark_safe(
                "<option value={url} {selected}>{text}</option>".format(url=url, selected=selected, text=text))
        yield mark_safe("</select>")


def issues(request, project_id):
    if request.method == "GET":
        # 对url跟参数进行数据筛选
        allow_lsit = ["status", "priority", "issues_type", "assign", "attention"]  # 规定只有这几个参数才能筛选
        data_dict = {}
        for item in allow_lsit:
            value_list = request.GET.getlist(item)
            if not value_list:  # 空列表就不加进字典
                continue
            data_dict["{}__in".format(item)] = value_list
        """
            data_dict= {
                'status__in': ['1', '2'],   
                'priority__in': ['3']
            }
        """
        # 注：fileter(字段__in=[1,2])可以查出这个字段=1or字段=2的数据
        # 查询出所有数据
        all_data = models.Issues.objects.filter(**data_dict,project_id=project_id)
        page_obj = Pagination(request, all_data)  # 实例化分页对象
        data_list = page_obj.data_queryset  # 分页后的数据
        page_str = page_obj.html()  # 返回翻页html标签
        form = IssuesModelForm(request)

        # 筛选模块
        project_issues_type = models.IssuesType.objects.filter(project_id=project_id).values_list('id', 'title')
        status_choices = models.Issues.status_choices
        priority_choices = models.Issues.priority_choices
        total_user = [(request.manage.creator_id, request.manage.creator.username), ]
        pro_user = models.ProjectUser.objects.filter(project=request.manage).values_list("user", "user__username")
        total_user.extend(pro_user)

        # 生成邀请码ModelForm
        invite_form = InviteModelForm()

        filter_list = [
            {"title": "问题类型", "filter": Checkfilt('issues_type', project_issues_type, request)},
            {"title": "状态", "filter": Checkfilt('status', status_choices, request)},
            {"title": "优先级", "filter": Checkfilt('priority', priority_choices, request)},
            {"title": "指派人", "filter": Selectfilt('priority', total_user, request)},
            {"title": "关注者", "filter": Selectfilt('attention', total_user, request)},
        ]
        return render(request, 'issues.html',
                      {"form": form, "invite_form": invite_form, "data_list": data_list, "page_str": page_str,
                       "filter_list": filter_list})
    form = IssuesModelForm(request, data=request.POST)
    if form.is_valid():
        form.instance.project = request.manage
        form.instance.creator = request.transaction.user
        form.save()
        return JsonResponse({"status": True})
    return JsonResponse({"status": False, "errors": form.errors})


def edit(request, project_id, issues_id):
    if request.method == "GET":
        data_obj = models.Issues.objects.filter(id=issues_id).first()
        form = IssuesModelForm(request, instance=data_obj)
        return render(request, "issues_edit.html", {"form": form, "issues_obj": data_obj})


@csrf_exempt
def record(request, project_id, issues_id):
    if request.method == "GET":
        all_data = models.IssuesReply.objects.filter(issues_id=issues_id)
        data_list = []
        for item in all_data:
            data_dict = {
                "id": item.id,
                "content": item.content,
                'reply_type_text': item.get_reply_type_display(),
                "creator": item.creator.username,
                "datetime": item.create_datetime.strftime("%Y-%m-%d %H:%M"),
                "parent_id": item.reply_id
            }
            data_list.append(data_dict)
        return JsonResponse({"status": True, "data_list": data_list})
    form = RecordModelForm(data=request.POST)
    if form.is_valid():
        form.instance.reply_type = 2  # 通过此请求产生的都是回复
        form.instance.issues_id = issues_id
        form.instance.creator = request.transaction.user
        instance = form.save()
        data_dict = {
            "id": instance.id,
            "content": instance.content,
            'reply_type_text': instance.get_reply_type_display(),
            "creator": instance.creator.username,
            "datetime": instance.create_datetime.strftime("%Y-%m-%d %H:%M"),
            "parent_id": instance.reply_id
        }
        return JsonResponse({"status": True, "data_dict": data_dict})
    return JsonResponse({"status": False, "errors": form.errors})


@csrf_exempt
def update(request, project_id, issues_id):
    issues_obj = models.Issues.objects.filter(id=issues_id, project_id=project_id).first()
    data = json.loads(request.body.decode('utf-8'))  # 因为前端发送数据会存在一个key对应多个值，过来后key名称会变，所以用这种方式取值
    name = data.get("name")
    value = data.get("value")
    colum_obj = models.Issues._meta.get_field(name)  # 得到字段对象

    def return_client(change_info):
        new_object = models.IssuesReply.objects.create(
            reply_type=1,
            issues=issues_obj,
            content=change_info,
            creator=request.transaction.user,
        )
        new_reply_dict = {
            'id': new_object.id,
            'reply_type_text': new_object.get_reply_type_display(),
            'content': new_object.content,
            'creator': new_object.creator.username,
            'datetime': new_object.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': new_object.reply_id
        }
        return new_reply_dict

    # 1.当为几个文本字段时，直接更新修改内容
    if name in ["subject", "desc", "start_date", "end_date"]:
        if not value:
            if not colum_obj.null:
                return JsonResponse({'status': False, 'error': "您选择的值不能为空"})
            setattr(issues_obj, name, value)
            issues_obj.save()
            change_info = "{}更新为空".format(colum_obj.verbose_name)
        else:
            setattr(issues_obj, name, value)
            issues_obj.save()
            # 记录：xx更为了value
            change_info = "{}更新为{}".format(colum_obj.verbose_name, value)

        return JsonResponse({'status': True, 'data': return_client(change_info)})

    # 1.2 FK字段（指派的话要判断是否创建者或参与者）
    if name in ['issues_type', 'module', 'parent', 'assign']:
        # 用户选择为空
        if not value:
            # 不允许为空
            if not colum_obj.null:
                return JsonResponse({'status': False, 'error': "您选择的值不能为空"})
            # 允许为空
            setattr(colum_obj, name, None)
            issues_obj.save()
            change_record = "{}更新为空".format(colum_obj.verbose_name)
        else:  # 用户输入不为空
            if name == 'assign':
                # 是否是项目创建者
                if value == str(request.manage.creator_id):
                    instance = request.manage.creator
                else:
                    project_user_object = models.ProjectUser.objects.filter(project_id=project_id,
                                                                            user_id=value).first()
                    if project_user_object:
                        instance = project_user_object.user
                    else:
                        instance = None
                if not instance:
                    return JsonResponse({'status': False, 'error': "您选择的值不存在"})

                setattr(issues_obj, name, instance)
                issues_obj.save()
                change_record = "{}更新为{}".format(colum_obj.verbose_name, str(instance))  # value根据文本获取到内容
            else:
                # 条件判断：用户输入的值，是自己的值。  外键字段对象.remote_field能关联到对应表
                instance = colum_obj.remote_field.model.objects.filter(id=value, project_id=project_id).first()
                if not instance:
                    return JsonResponse({'status': False, 'error': "您选择的值不存在"})

                setattr(issues_obj, name, instance)
                issues_obj.save()
                change_record = "{}更新为{}".format(colum_obj.verbose_name, str(instance))  # value根据文本获取到内容

        return JsonResponse({'status': True, 'data': return_client(change_record)})

    # 1.3 choice字段（比对是否和选项的id相同）
    if name in ["status", "priority", "mode"]:
        choice_list = colum_obj.choices
        select_txt = None
        for key, text in choice_list:
            if value == str(key):
                select_txt = text
        if not select_txt:
            return JsonResponse({'status': False, 'error': "您选择的值有误"})
        setattr(issues_obj, name, value)
        issues_obj.save()
        change_info = '{}更新为{}'.format(colum_obj.verbose_name, select_txt)
        return JsonResponse({'status': True, 'data': return_client(change_info)})

    # 1.4 m2m字段
    if name == "attention":
        if not isinstance(value, list):  # 判断传回来的value是不是列表
            return JsonResponse({'status': False, 'error': "数据格式错误"})
        if not value:  # 判断是否是空列表
            return JsonResponse({'status': False, 'error': "选项不能为空"})
        else:
            # 有值的话，进行判断是否合法，即是否为为项目创建者和参与者
            user = request.manage.creator
            join_list = models.ProjectUser.objects.filter(project_id=project_id)
            user_dict = {str(user.id): user.username}
            for item in join_list:  # 将参与者和创建者组成一个id:username的字典用于轮询对比value的值是否属于里面的
                user_dict[str(item.user_id)] = item.user.username
            username_list = []
            for i in value:
                if not user_dict.get(str(i)):
                    return JsonResponse({'status': False, 'error': "选项为非正确项"})
                username_list.append(user_dict.get(str(i)))
            issues_obj.attention.set(value)  # m2m数据保存是用行对象.字段.set(值)
            issues_obj.save()
            change_record = "{}更新为{}".format(colum_obj.verbose_name, ','.join(username_list))  # 给名字用符号分割连成字符串
            return JsonResponse({'status': True, 'data': return_client(change_record)})

    return JsonResponse({"status": True})


def invite(request, project_id):
    form = InviteModelForm(data=request.POST)
    # 生成随机验证码
    invite_code = uid(request.manage.creator.mobile_phone)
    if form.is_valid():
        if request.transaction.user != request.manage.creator:
            form.add_error("period", "当前账户无权进行邀请")
            return JsonResponse({"status": False, "errors": form.errors})
        form.instance.project = request.manage
        form.instance.code = invite_code
        form.instance.creator = request.transaction.user
        form.save()
        url = "{scheme}://{host}{path}".format(
            scheme=request.scheme,
            host=request.get_host(),
            path=reverse("invite_join", kwargs={"code": invite_code})
        )
        print(url)
        return JsonResponse({"status": True, "data": url})
    return JsonResponse({"status": False, "errors": form.errors})


def invite_join(request, code):
    """ 访问邀请码 """
    invite_obj = models.ProjectInvite.objects.filter(code=code).first()
    # 判断验证码是否存在
    exist = models.ProjectInvite.objects.filter(code=code).exists()
    if not exist:
        return render(request, "join.html", {"error": "邀请验证码无效"})
    # 判断当前登录人是否是此项目创建者
    if invite_obj.creator == request.transaction.user:
        return render(request, "join.html", {"error": "项目创建者无需加入"})
    # 判断当前登录人是否已经加入
    exist_join = models.ProjectUser.objects.filter(user=request.transaction.user).exists()
    if exist_join:
        return render(request, "join.html", {"error": "已加入过此项目，无法重新加入"})
    # 判断邀请码是否过期
    current_datetime = datetime.datetime.now()  # 获取现在时间
    limit_data = invite_obj.create_datetime + datetime.timedelta(minutes=invite_obj.period)  # 过期时间
    if current_datetime > limit_data.replace(tzinfo=None):
        return render(request, "join.html", {"error": "验证码过期"})
    # 数量限制
    if invite_obj.count:
        if invite_obj.count <= invite_obj.use_count:
            return render(request, "join.html", {"error": "当前邀请人数已满"})
        invite_obj.use_count += 1  # 没有设数量限制，也不给使用人数增加了
        invite_obj.save()

    models.ProjectUser.objects.create(user=request.transaction.user, project=invite_obj.project)
    print(invite_obj.project)
    return render(request, 'join.html', {'project': invite_obj.project})
